﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Collections;

namespace SynoManager.FileStation.Tasks
{
    public class TaskQueue : IBindingList
    {
        private List<TaskBase> tasks = new List<TaskBase>();
        private TaskBase current = null;
        private FileStationService service;

        public event EventHandler<TaskEventArgs> TaskProgressChanged;
        public event EventHandler<TaskEventArgs> TaskCompleted;
        public event ListChangedEventHandler ListChanged;

        public TaskQueue(FileStationService service)
        {
            this.service = service;
        }

        public void Add(TaskBase task)
        {
            task.Queue = this;
            tasks.Add(task);
            if (ListChanged != null)
                ListChanged(this, new ListChangedEventArgs(ListChangedType.ItemAdded, tasks.IndexOf(task)));

            TryProcessNext();
        }

        public TaskBase CurrentTask
        {
            get { return current;}
        }

        public FileStationService Service
        {
            get { return service; }
        }

        private void TryProcessNext()
        {
            Debug.WriteLine("TryProcessNext()", "TaskQueue");
            if (current != null && current.State == TaskState.Executing)
                return;

            foreach(TaskBase task in tasks)
            {
                if (task.State == TaskState.Pending)
                {
                    Execute(task);
                    break;
                }
            }
        }

        private void Execute(TaskBase task)
        {
            Debug.WriteLine("Execute(" + task.DisplayTitle + ")", "TaskQueue");
            current = task;
            task.State = TaskState.Executing;
            if (ListChanged != null)
                ListChanged(this, new ListChangedEventArgs(ListChangedType.ItemChanged, tasks.IndexOf(task)));
            ThreadPool.QueueUserWorkItem(ExecuteThread, task);
        }

        private void ExecuteThread(object state)
        {
            TaskBase task = (TaskBase) state;
            task.Execute();
        }

        internal void SetCompleted(TaskBase task)
        {
            Debug.WriteLine("Task Completed (" + task.DisplayTitle + ")", "TaskQueue");

            if (TaskCompleted != null)
                TaskCompleted(this, new TaskEventArgs(task));

            if (ListChanged != null)
                ListChanged(this, new ListChangedEventArgs(ListChangedType.ItemChanged, tasks.IndexOf(task)));

            TryProcessNext();
        }

        internal void UpdateProgress(TaskBase task, double percentageComplete)
        {
            Debug.WriteLine("Task Progress Changed (" + task.DisplayTitle + ": " + percentageComplete + ")", "TaskQueue");

            if (TaskProgressChanged != null)
                TaskProgressChanged(this, new TaskEventArgs(task));
            if (ListChanged != null)
                ListChanged(this, new ListChangedEventArgs(ListChangedType.ItemChanged, tasks.IndexOf(task)));
        }


        #region IBindingList Members

        void IBindingList.AddIndex(PropertyDescriptor property)
        {
            throw new NotImplementedException();
        }

        object IBindingList.AddNew()
        {
            throw new NotImplementedException();
        }

        bool IBindingList.AllowEdit
        {
            get { return false; }
        }

        bool IBindingList.AllowNew
        {
            get { return false; }
        }

        bool IBindingList.AllowRemove
        {
            get { return false; }
        }

        void IBindingList.ApplySort(PropertyDescriptor property, ListSortDirection direction)
        {
            throw new NotImplementedException();
        }

        int IBindingList.Find(PropertyDescriptor property, object key)
        {
            throw new NotImplementedException();
        }

        bool IBindingList.IsSorted
        {
            get { return true; }
        }

        void IBindingList.RemoveIndex(PropertyDescriptor property)
        {
            throw new NotImplementedException();
        }

        void IBindingList.RemoveSort()
        {
            throw new NotImplementedException();
        }

        ListSortDirection IBindingList.SortDirection
        {
            get { throw new NotImplementedException(); }
        }

        PropertyDescriptor IBindingList.SortProperty
        {
            get { throw new NotImplementedException(); }
        }

        bool IBindingList.SupportsChangeNotification
        {
            get { return true; }
        }

        bool IBindingList.SupportsSearching
        {
            get { return false; }
        }

        bool IBindingList.SupportsSorting
        {
            get { return false; }
        }

        #endregion

        #region IList Members

        int IList.Add(object value)
        {
            throw new NotImplementedException();
        }

        void IList.Clear()
        {
            throw new NotImplementedException();
        }

        bool IList.Contains(object value)
        {
            throw new NotImplementedException();
        }

        int IList.IndexOf(object value)
        {
            throw new NotImplementedException();
        }

        void IList.Insert(int index, object value)
        {
            throw new NotImplementedException();
        }

        bool IList.IsFixedSize
        {
            get { throw new NotImplementedException(); }
        }

        bool IList.IsReadOnly
        {
            get { throw new NotImplementedException(); }
        }

        void IList.Remove(object value)
        {
            throw new NotImplementedException();
        }

        void IList.RemoveAt(int index)
        {
            throw new NotImplementedException();
        }

        object IList.this[int index]
        {
            get
            {
                return tasks[index];
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        #endregion

        #region ICollection Members

        void ICollection.CopyTo(Array array, int index)
        {
            throw new NotImplementedException();
        }

        int ICollection.Count
        {
            get { return tasks.Count; }
        }

        bool ICollection.IsSynchronized
        {
            get { throw new NotImplementedException(); }
        }

        object ICollection.SyncRoot
        {
            get { throw new NotImplementedException(); }
        }
        #endregion

        #region IEnumerable Members

        IEnumerator IEnumerable.GetEnumerator()
        {
            return tasks.GetEnumerator();
        }

        #endregion
    }

    public class TaskEventArgs : EventArgs
    {
        public TaskBase Task { get; set; }

        public TaskEventArgs(TaskBase task)
        {
            Task = task;
        }
    }
}
